#+Title: Outline of Jul-mode

* Basic Outline of jul-mode
	This will contain the basic concepts behind the mode. Things like how it
	should look, how it should act, and what it should do will be discussed.

** Appearance
	 The appearance of the mode will be similar to list-package-mode in emacs.
	 There will be a package name, version, status, repo, and (maybe) a
	 description column. Here a spreadsheet of kinda how it would look:
   |   | Package | Version | Status    | Repository  | Description                 |
   |---+---------+---------+-----------+-------------+-----------------------------|
   | I | abiword |   3.0.0 | old-table | frusen      | A minimal word processor    |
   |   | dillo   |   3.0.5 | stable    | frusen      | A minimal web browser       |
   |   | sbcl    |   1.3.1 | unstable  | frusen      | Steel Bank Common Lisp      |
   | R | jwm     |     2.1 | stable    | kelsoo      | Joe's Window Manager        |
   |   | jwm     |   2.2.1 | stable    | kelsoo      | Joe's Window Manager        |
   |   | emacs   |    24.4 | stable    | mprodrigues | The greatest OS of all time |
   |   | dwm     |     6.1 |           | installed   | A lightweight WM            |
   |---+---------+---------+-----------+-------------+-----------------------------|
	 You can see that if there are 2 versions, it will list both. The status for
	 kelsoo's and mprodrigues' repos are actually unknown but I'm sure they're
	 stable. Also note that it will show all installed packages on the system and
	 the repo is "installed." There is no status on these. The first column in an
	 indicator column that lets you know if you have selected that package for
	 installation, removal, or upgrading. *NOTE: DESCRIPTION MOST LIKELY WON'T BE
	 THERE!*

*** Other Appearances
		The main buffer is what people will probably use most; however, if you which
		to filter the packages by repo or status, this should be able to be done.
		This would be really nice to see all the installed packages on your
		computer.

		Along with filtering, if there is a new version of a package that you have
		installed, it will be marked with an asterisks and at the top of the list.
		Even if you don't wish to installed it, it is nice to see that there is a
		new version in the repo.

		There will also be a "more info" buffer that you can bring up on a package
		(if there is more info). In this buffer there will be a plain text
		description. The minibuffer will show some of the commands you may wish to
		use on that package. For example, "I - install, R - remove."

** Functionality
	 While on the main list buffer, you can move like you normally would in emacs.
	 However, if you press RET on one of the packages a new buffer will open
	 containing more information (if available) about that package. As mentioned
	 before, the minibuffer will display some of the commands you may want to use
	 on that package. Of course, just press the key to do that option. While on
	 the main list buffer, you can press any of the command keys to choose to
	 installed, remove, or upgrade that package. To remove an item from
	 installation, removal, or upgrading, you can press that same command key
	 again. To actually go through with the selection, press 'X'.

	 Another important thing to note is that upon opening jul-mode, it will fetch
	 the repos and update them. That being said, if there is a new package for a
	 program that is installed, the minibuffer will say something like "Press 'U'
	 to select all (n) packages for upgrade." where 'n' is the number of packages
	 that need upgraded. This makes it easy to know when you can upgrade you
	 software and makes it easy to upgrade.

	 It should also be noted that jul-mode will be able to remove installed
	 packages from the system. This will make package manager even better.


* list-packages
** If packages are *not* initialized
	 Calls an initialization function (l. 2084)
*** package-initialize
		This function loads the package descriptions and read the archive contents
		Whatever that means...
*** package-refresh-contents (l. 1314)
		After doing some things with gpg keys, it looks at the package-archives list
		and downloads stuff from them using the following function.
**** package--download-one-archive (l. 1332)
		 Shit hits the fan because nothing makes sense.


* jul-mode stuff
	So far I know that I can use the following command to get the HTML code from
	the site:
	(with-temp-file "foo.txt" (url-insert-file-contents "http://gungre.ch/dragora/repo/frusen/old-stable"))
	That's as far as I am right now.

	Just a hint, use the buffer creation and something like this:
	#+BEGIN_SRC emacs-lisp
	(with-current-buffer buf
      (package-menu-mode)
      (package-menu--generate nil packages keywords))
	#+END_SRC
	Except using jul related functions instead of package-menu ones.

** Archive
	 This is a custom list that contains all the archives to look at when grabbing
	 new packages.
	 #+BEGIN_SRC emacs-lisp
(eval-when-compile (require 'cl-lib))

(require 'tabulated-list)

(defgroup jul-package nil
  "Manager for Dragora User packages."
  :group 'applications
  :version "0.1")

	 (defcustom jul-package-archives
	 '(("frusen-stable" . "http://gungre.ch/dragora/repo/frusen/stable/")
		("frusen-oldstable" . "http://gungre.ch/dragora/repo/frusen/old-stable/")
		("frusen-unstable" . "http:///gungre.ch/dragora/repo/frusen/unstable/")
		("kelsoo" . "http:///gungre.ch/dragora/repo/kelsoo")
		("mp" . "http:///gungre.ch/dragora/repo/frusen/mprodrigues/"))
  "An alist of archives from which to fetch.
The defaults include all the repos found on the gungre.ch site.
Note that frusen has 3 different ones.

Each element has the form (ID . LOCATION).
 ID is an archive name, as a string.
 LOCATION specifies the base location for the archive.
  If it starts with \"http:\", it is treated as a HTTP URL;
  otherwise it should be an absolute directory name.
  (Other types of URL are currently not supported.)

Only add locations that you trust, since fetching and installing
a package can run arbitrary code."
  :type '(alist :key-type (string :tag "Archive name")
                :value-type (string :tag "URL or directory name"))
  :risky t
  :group 'jul-package
  :version "0.1")
	 #+END_SRC

** Package Lists
	 #+BEGIN_SRC emacs-lisp
(cl-defstruct (jul-package-desc
               ;; Rename the default constructor from `make-package-desc'.
               (:constructor jul-package-desc-create)
               ;; Has the same interface as the old `define-package',
               ;; which is still used in the "foo-pkg.el" files. Extra
               ;; options can be supported by adding additional keys.
               (:constructor
                jul-package-desc-from-define
                (name-string version-string repo-string
                 &aux
                 (name (intern name-string))
                 (version version-string)
                 (repo repo-string))))
  "Structure containing information about an individual package.
Slots:

`name'	Name of the package, as a symbol.

`version' Version of the package, as a string

`repo' The name of the archive (as a string) whence this
	package came."
  name
  version
  repo)

	 #+END_SRC
** Buffer Creation
	#+BEGIN_SRC emacs-lisp
(define-derived-mode jul-menu-mode tabulated-list-mode "Jul Package Menu"
	"Major mode for browsing a list of packages"
	(setq tabulated-list-format
        `[("Package" 18 nil) ;there will eventually be something here instead of nil
          ("Version" 13 nil)
          ("Status"  10 nil)
          ,@(if (cdr jul-package-archives)
                '(("Repo" 10 nil)))
          ("Description" 0 nil)])
	(setq tabulated-list-padding 2)
  (setq tabulated-list-sort-key (cons "Status" nil))
;; There will be some sort of refreshing thing
;  (add-hook 'tabulated-list-revert-hook 'package-menu--refresh nil t)
  (tabulated-list-init-header))

(defun test-buffer (&optional packages)
	(interactive)
	(let* ((buf (get-buffer-create "*jul-package-list*"))
				 (win (get-buffer-window buf)))
		(with-current-buffer buf
      (jul-menu-mode)  ;this is in the archives section
      (package-menu--generate nil packages)) ;found in package list generation section
		(if win
				(select-window win)
			(switch-to-buffer buf))))
	#+END_SRC

** Package List Generation
	 I need special lists of all the installed packages and all the ones on the
	 server. the `jul-package-menu--refresh' function update the lists.
	 #+BEGIN_SRC emacs-lisp
(defvar jul-package-installed nil
	"This list contains all the packages that are currently installed on your
system. Each element is of the form (NAME . J-PKG-DESC) where NAME is the name
of the package and J-PKG-DESC is a cl-struct-jul-package-desc.")

(defvar jul-package-repo nil
	"This list contains all the packages that are currently on the gungre.ch
server. Each element is of the form (NAME . J-PKG-DESC) where NAME is the name
of the package and J-PKG-DESC is a cl-struct-jul-package-desc.")

(defmacro jul-package--push (pkg-desc listname)
  "Convenience macro for `jul-package-menu--generate'.
If the alist stored in the symbol LISTNAME lacks an entry for a
package PKG-DESC, add one.  The alist is keyed with PKG-DESC."
  `(unless (assoc ,pkg-desc ,listname)
     ;; FIXME: Should we move status into pkg-desc?
     (push ,pkg-desc ,listname)))

(defun jul-package-menu--print-info (pkg)
  (let* ((pkg-desc (car pkg))
         (name (jul-package-desc-name pkg-desc))
         (version (jul-package-desc-version pkg-desc)))
     `(,pkg-desc (list name version))))

(defun jul-package-menu--refresh (&optional packages)
  (unless packages (setq packages t))
  (let (info-list name)
    ;; Installed packages:
    (dolist (elt jul-package-alist) ;needs to be updated before this
      (setq name (car elt))
      (when (or (eq packages t) (memq name packages))
        (dolist (pkg (cdr elt))
           (jul-package--push pkg info-list))))

    ;; Uninstalled Packages:
    (dolist (elt jul-package-repo) ;needs to be updated before this
      (setq name (car elt))
      (when (or (eq packages t) (memq name packages))
        (dolist (pkg (cdr elt))
           (jul-package--push pkg info-list))))

    (setq tabulated-list-entries
        (mapcar #'jul-package-menu--print-info info-list))))

(defun jul-package-menu--generate (remember-pos packages)
  "Populate the Package Menu.
 If REMEMBER-POS is non-nil, keep point on the same entry.
PACKAGES should be t, which means to display all known packages,
or a list of package names (symbols) to display."
  (jul-package-menu--refresh packages) ;refreshes the tabulated-list-entries list
  (setf (car (aref tabulated-list-format 0)) "Package")
  (tabulated-list-init-header)
  (tabulated-list-print remember-pos))
	 #+End_SRC

** Upgrading
	 In order to upgrade, you must first have the program installed. Thus, I need
	 to first check to see if there is a version of the program installed. It
	 musted be check for every program (this could take some time). Then we must
	 see if the version you have installed is older or not. If so, set the upgrade
	 flag. Then 'pkg upgrade foo.tlz' will be ran in the upgrading function.

* Remember this stuff

	Because I don't have parsing from the server working yet, you have to manually
	set the "global" variables `*jul-package-installed*' and `*jul-package-repo*'.
	The best way to do this is using eshell and running the following commands:

	#+BEGIN_SRC emacs-lisp
(setf repo (cons (cons "sbcl" (jul-package-desc-from-define "sbcl" "1.3.1" "frusen-unstable")) repo))
	#+End_SRC

	Then change the values and all that good stuff. Then make another variable
	called `installed' or something. Then you can easily "setf" those variables!
